package com.chaos.gateway.config.interceptor;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chaos.framework.model.constant.Constants;
import feign.Feign;
import feign.Logger;
import feign.RequestInterceptor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.nio.charset.Charset;

@EnableDiscoveryClient
@Configuration
@Slf4j
public class OpenFeignInterceptor {
    private static final Charset UTF8 = Charset.forName("UTF-8");

    @Bean
    Logger.Level lever() {
        return Logger.Level.FULL;
    }


    @Bean
    public okhttp3.OkHttpClient okHttpClient() {
        return new okhttp3.OkHttpClient.Builder()
                .addInterceptor(new LoggingInterceptor()).build();
    }

    @Bean
    public RequestInterceptor feignRequestInterceptor() {
        return new OpenFeignRequestInterceptor();
    }


    @Bean
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    }

    static class LoggingInterceptor implements Interceptor {

        @NotNull
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long start = System.nanoTime();
            String requestBody = requestBodyToString(request.body());
            Response response = chain.proceed(request);
            String responseBody = responseBodyToString(response.body());
            JSONObject requestJson;
            JSONObject responseJson;
            if (StringUtils.isBlank(requestBody)) {
                requestJson = new JSONObject();
            } else {
                requestJson = JSON.parseObject(requestBody);
            }
            if (StringUtils.isBlank(requestBody)) {
                responseJson = new JSONObject();
            } else {
                responseJson = JSON.parseObject(requestBody);
            }
            responseJson = JSON.parseObject(responseBody);

            long end = System.nanoTime();
            log.info(String.format("%n" +
                            "Sending request %s in %.1fms %n" +
                            "Request traceId: %s%n" +
                            "RequestBody: %s%n" +
                            "ResponseBody: %s",
                    request.url(), (end - start) / 1e6d,
                    request.headers().get(Constants.TRACE_ID),
                    requestJson.toJSONString(),
                    responseJson.toJSONString()));
            return response;
        }

        public static String requestBodyToString(RequestBody requestBody) throws IOException {
            Buffer buffer = new Buffer();
            requestBody.writeTo(buffer);
            return buffer.readUtf8();
        }

        public static String responseBodyToString(ResponseBody responseBody) throws IOException {
            long contentLength = responseBody.contentLength();
            if (contentLength == 0) {
                return "";
            }
            BufferedSource source = responseBody.source();
            source.request(Long.MAX_VALUE);
            Buffer buffer = source.buffer();

            String result = buffer.clone().readString(UTF8);
            return result;

        }

    }

}
